/**
 * Copyright (C) 2021 - 2031 O-Cubes Co., Ltd.
 */

/****************************************************************
 *  @file    pcl.c
 *  @brief   PCL driver
 *  @version v1.0
 *  @date    03. Apr. 2023
 *  @author  gonght
 ****************************************************************/

#include "pcl.h"
#include "io.h"
#include "autoconf.h"

static unsigned int pcl_reg_read(volatile uint32_t pcl_reg_addr)
{
	if (!pcl_reg_addr) {
		return 0;
	}

	return readl(pcl_reg_addr);
}

static void pcl_reg_write(uint32_t value, volatile uint32_t pcl_reg_addr)
{
	if (pcl_reg_addr) {
		writel(value, pcl_reg_addr);
	}
}

void pcl_set_spi3_tf(pcl_spi_tf tf)
{
	uint32_t reg_val;

	if (PCL_SPI_TF_STD == tf) {
		/* set spi2 dual/quad mode */
		reg_val = pcl_reg_read(PCL_TFS_CTL_ADDR);
		reg_val = reg_val | PCL_TFS_CTL_SPI3_SEL;
		pcl_reg_write(reg_val, PCL_TFS_CTL_ADDR);
	} else if (PCL_SPI_TF_QUAD == tf) {
		/* set spi2 standard mode */
		reg_val = pcl_reg_read(PCL_TFS_CTL_ADDR);
		reg_val = reg_val & ~PCL_TFS_CTL_SPI3_SEL;
		pcl_reg_write(reg_val, PCL_TFS_CTL_ADDR);
	}
}

void pcl_set_spi_wire_mode(pcl_spi_dev_id spi_id, pcl_spi_wire_mode mode)
{
	uint32_t reg_val;
	uint32_t bit_val ;

	if (spi_id == PCL_SPI_DEV_ID0) {
		bit_val = PCL_TFS_CTL_SPI0_SEL;
	} else if (spi_id == PCL_SPI_DEV_ID1 || spi_id == PCL_SPI_DEV_ID2) {
		bit_val = PCL_TFS_CTL_SPI1_2_SEL;
	} else {
		return;
	}

	if (PCL_SPI_THREE_WIRE_MODE == mode) {
		/* set spi three wire mode */
		reg_val = pcl_reg_read(PCL_TFS_CTL_ADDR);
		reg_val = reg_val | bit_val;
		pcl_reg_write(reg_val, PCL_TFS_CTL_ADDR);
	} else if (PCL_SPI_FOUR_WIRE_MODE == mode) {
		/* set spi four wire mode */
		reg_val = pcl_reg_read(PCL_TFS_CTL_ADDR);
		reg_val = reg_val & ~bit_val;
		pcl_reg_write(reg_val, PCL_TFS_CTL_ADDR);
	}
}

void pcl_func_select(uint32_t pad_id, pcl_func_sel func)
{
	uint32_t reg_val;

	reg_val = pcl_reg_read(PCL_SWPORT_IOCTL_ADDR(pad_id));
	reg_val &= ~(PCL_SWPORT_IOCTL_FUN_SEL(PCL_SELECT_MAX));
	pcl_reg_write(reg_val | PCL_SWPORT_IOCTL_FUN_SEL(func), PCL_SWPORT_IOCTL_ADDR(pad_id));
}

pcl_func_sel pcl_func_get(uint32_t pad_id)
{
	uint32_t reg_val;
	pcl_func_sel func = PCL_SELECT_FUNC1;

	reg_val = pcl_reg_read(PCL_SWPORT_IOCTL_ADDR(pad_id));
	func = (reg_val >> 2) & 0x7;

	return func;
}

void pcl_pd_pu_set(uint32_t pad_id, pcl_pd_pu_cfg cfg)
{
	uint32_t reg_val;

	reg_val = pcl_reg_read(PCL_SWPORT_IOCTL_ADDR(pad_id));
	if (cfg == PCL_PDPU_CFG_ENABLE)
		reg_val &= ~PCL_SWPORT_IOCTL_REN;
	else
		reg_val |= PCL_SWPORT_IOCTL_REN;

	pcl_reg_write(reg_val, PCL_SWPORT_IOCTL_ADDR(pad_id));
}

void pcl_pin_output_set(uint32_t pad_id, pcl_pin_output_cfg cfg)
{
	uint32_t reg_val;

	reg_val = pcl_reg_read(PCL_SWPORT_IOCTL_ADDR(pad_id));
	if (cfg == PCL_PIN_OUTPUT_ENABLE)
		reg_val &= ~PCL_SWPORT_IOCTL_OEN;
	else
		reg_val |= PCL_SWPORT_IOCTL_OEN;

	pcl_reg_write(reg_val, PCL_SWPORT_IOCTL_ADDR(pad_id));
}



void pcl_init(void)
{
	//uart0
	pcl_func_select(PAD_ID_GPIO06, PAD018_FUNC_UART0_TXD);
	pcl_func_select(PAD_ID_GPIO07, PAD019_FUNC_UART0_RXD);

#ifdef CONFIG_SDK_SDADC
	//spi0
	pcl_func_select(PAD_ID_GPIO02, PAD014_SPI0_CSN);
	pcl_func_select(PAD_ID_GPIO03, PAD015_SPI0_CLK);
	pcl_func_select(PAD_ID_GPIO04, PAD016_SPI0_SDIO);
	pcl_func_select(PAD_ID_GPIO05, PAD017_SPI0_SDO);
	//spi1
	pcl_func_select(PAD_ID_GPIO08, PAD020_FUNC_SPI1_CSN);
	pcl_func_select(PAD_ID_GPIO09, PAD021_FUNC_SPI1_CLK);
	pcl_func_select(PAD_ID_GPIO10, PAD022_FUNC_SPI1_SDIO);
	pcl_func_select(PAD_ID_GPIO11, PAD023_FUNC_SPI1_SDO);
#else
	//uart4
	pcl_func_select(PAD_ID_GPIO08, PAD020_FUNC_UART4_TXD);
	pcl_func_select(PAD_ID_GPIO09, PAD021_FUNC_UART4_RXD);
	pcl_func_select(PAD_ID_GPIO10, PAD022_FUNC_UART4_RTS);
	pcl_func_select(PAD_ID_GPIO11, PAD023_FUNC_UART4_CTS);
#endif

	//uart2
	pcl_func_select(PAD_ID_GPIO12, PAD024_FUNC_UART2_TXD);
	pcl_func_select(PAD_ID_GPIO13, PAD025_FUNC_UART2_RXD);

	//gpio15 gpio17
	pcl_func_select(PAD_ID_GPIO15, PAD027_FUNC_GPIO15);
	pcl_func_select(PAD_ID_GPIO17, PAD029_FUNC_GPIO17);

	//spi0
	pcl_func_select(PAD_ID_GPIO02, PAD014_SPI0_CSN);
	pcl_pin_output_set(PAD_ID_GPIO02, PCL_PIN_OUTPUT_ENABLE);
	pcl_func_select(PAD_ID_GPIO03, PAD015_SPI0_CLK);
	pcl_pin_output_set(PAD_ID_GPIO03, PCL_PIN_OUTPUT_ENABLE);
	pcl_func_select(PAD_ID_GPIO05, PAD017_SPI0_SDO);
	pcl_pin_output_set(PAD_ID_GPIO05, PCL_PIN_OUTPUT_ENABLE);


	//i2c0
	pcl_func_select(PAD_ID_GPIO00, PAD012_FUNC_I2C0_SCL);
	pcl_func_select(PAD_ID_GPIO01, PAD013_FUNC_I2C0_SDA);
	//pcl_set_spi3_tf(PCL_SPI_TF_QUAD);

}


pcl_boot_mod pcl_get_bootmod(void)
{
	return pcl_reg_read(PCL_BOOT_VAL_ADDR);
}
